import base64
import os
import uuid

import gradio as gr
import modelscope_studio.components.antd as antd
import modelscope_studio.components.antdx as antdx
import modelscope_studio.components.base as ms
import modelscope_studio.components.pro as pro
from modelscope_studio.components.pro.chatbot import (ChatbotActionConfig,
                                                      ChatbotBotConfig,
                                                      ChatbotUserConfig,
                                                      ChatbotWelcomeConfig)
from modelscope_studio.components.pro.multimodal_input import \
  MultimodalInputUploadConfig
from openai import OpenAI
from meeting import get_transcription, get_summary,get_translation
from safety import get_safe_summary,get_safe_transcription
# =========== Configuration

# API KEY
MODELSCOPE_ACCESS_TOKEN = os.getenv('abc123')

client = OpenAI(
    base_url='https://brilliant-millennium-9738-8080.east4.casdao.com/v1/',
    api_key='abc123',
)

model = "Qwen2.5-1.5B-Instruct"

save_history = False

# =========== Configuration

# DEFAULT_PROMPTS = [{
#     "label":
#     # 翻译一下
#     "📅 帮我做个计划",
#     "children": [{
#         "description": "Help me with a plan to start a business",
#     }, {
#         "description": "Help me with a plan to achieve my goals",
#     }, {
#         "description":
#         "Help me with a plan for a successful interview",
#     }]
# }, {
#     "label":
#     "🖋 帮我写",
#     "children": [{
#         "description": "SHelp me write a story with a twist ending",
#     }, {
#         "description": "Help me write a blog post on mental health",
#     }, {
#         "description": "Help me write a letter to my future self",
#     }]
# }]

DEFAULT_SUGGESTIONS = []

DEFAULT_LOCALE = 'zh_CN'

DEFAULT_THEME = {
    "token": {
        "colorPrimary": "#6A57FF",
    }
}


def user_config(disabled_actions=None):
    """
    创建聊天机器人用户配置。

    该函数定义了一个用户配置，其中包括一组可执行的动作和禁用的动作。
    可执行的动作包括 'copy', 'edit' 以及一个带有弹出确认框的 'delete' 动作。

    参数:
    - disabled_actions: 一个包含禁用动作的列表。如果不需要禁用任何动作，该参数可以为空列表或 None。

    返回值:
    返回一个 ChatbotUserConfig 对象，该对象包含了聊天机器人用户的配置。
    """
    # 配置 'delete' 动作的弹出确认框属性
    delete_action_config = ChatbotActionConfig(
        action="delete",
        popconfirm=dict(title="删除该消息",
                        description="确定删除该条消息吗?",
                        okButtonProps=dict(danger=True))
    )

    # 创建并返回 ChatbotUserConfig 对象
    return ChatbotUserConfig(actions=[
        "copy", "edit", delete_action_config
    ], disabled_actions=disabled_actions)


def bot_config(disabled_actions=None):
    """
    生成聊天机器人的配置对象。

    参数:
    - disabled_actions: 可选参数，指定禁用的操作列表。如果未提供，则默认为None。

    返回:
    - ChatbotBotConfig实例，用于配置聊天机器人的行为和外观。
    """
    # 创建并返回聊天机器人的配置对象
    return ChatbotBotConfig(
        # 定义机器人支持的操作列表
        actions=[
            "copy", "like", "dislike", "edit",
            # 配置“重试”操作，并包含一个弹出确认框的设置
            ChatbotActionConfig(
                action="retry",
                popconfirm=dict(
                    title="重新生成消息",
                    description= "重新生成此条消息",
                    okButtonProps=dict(danger=True))),
            # 配置“删除”操作，并包含一个弹出确认框的设置
            ChatbotActionConfig(action="delete",
                                popconfirm=dict(
                                    title="删除该消息",
                                    description= "确定删除该消息?",
                                    okButtonProps=dict(danger=True)))
        ],
        # 设置机器人的头像URL
        avatar= "./icon.png",
        # 设置禁用的操作列表
        disabled_actions=disabled_actions)


class Gradio_Events:

    @staticmethod
    def submit(state_value):
        """
        提交用户消息并生成助手回复。

        参数:
        - state_value: 当前对话的状态值，包含会话历史和当前会话ID等信息。

        逻辑步骤:
        1. 定义辅助函数 `image_to_base64`，将图片文件转换为Base64编码的字符串。
        2. 定义辅助函数 `format_history`，将会话历史格式化为模型所需的输入格式。
        3. 获取当前会话的历史记录，并调用 `format_history` 函数将其转换为模型输入。
        4. 在历史记录中添加一条新的助手消息，状态设置为“加载中”。
        5. 调用模型生成助手回复，支持流式传输。
        6. 实时更新助手消息内容，并在生成完成后设置状态为“完成”。
        7. 如果生成过程中发生异常，捕获异常并返回错误提示。

        返回:
        - 生成器对象，逐步更新聊天界面和状态值。
        """

        # 将图片文件路径转换为Base64编码的字符串
        def image_to_base64(image_path):
            with open(image_path, "rb") as image_file:
                encoded_string = base64.b64encode(
                    image_file.read()).decode('utf-8')
            return f"data:image/jpeg;base64,{encoded_string}"

        # 格式化会话历史为模型输入格式
        def format_history(history):
            messages = [{
                "role": "system",
                "content": "你的名字是北京铁路局铁语通助手,可以帮助用户了解想要的信息。",
            }]
            for item in history:
                if item["role"] == "user":
                    messages.append({
                        "role": "user",
                        "content": [{
                            "type": "image_url",
                            "image_url": image_to_base64(file)
                        } for file in item["content"][0]["content"]
                                    if os.path.exists(file)] + [{
                            "type": "text",
                            "text": item["content"][1]["content"]
                        }]
                    })
                elif item["role"] == "assistant":
                    messages.append({
                        "role": "assistant",
                        "content": item["content"]
                    })
            return messages

        # 获取当前会话的历史记录
        history = state_value["conversations_history"][
            state_value["conversation_id"]]
        history_messages = format_history(history)

        # 添加一条新的助手消息，状态设置为“加载中”
        history.append({
            "role": "assistant",
            "content": "",
            "loading": True,
            "status": "pending"
        })

        # 更新聊天界面和状态值
        yield {
            chatbot: gr.update(value=history),
            state: gr.update(value=state_value),
        }

        try:
            # 调用模型生成助手回复
            response = client.chat.completions.create(
                model=model,  # ModelScope 模型ID
                messages=history_messages,
                stream=True
            )
            for chunk in response:
                # 实时更新助手消息内容
                history[-1]["content"] += chunk.choices[0].delta.content
                history[-1]["loading"] = False
                yield {
                    chatbot: gr.update(value=history),
                    state: gr.update(value=state_value)
                }
            # 设置助手消息状态为“完成”
            history[-1]["status"] = "done"
            yield {
                chatbot: gr.update(value=history),
                state: gr.update(value=state_value),
            }
        except Exception as e:
            # 捕获异常并返回错误提示
            history[-1]["loading"] = False
            history[-1]["status"] = "done"
            history[-1]["content"] = "Failed to respond, please try again."
            yield {
                chatbot: gr.update(value=history),
                state: gr.update(value=state_value)
            }
            raise e

    @staticmethod
    def add_user_message(input_value, state_value):
        """
        添加用户消息到对话历史中。
    
        当对话ID不存在时，生成一个新的对话ID，并初始化对话历史。
        将用户的消息添加到对应的对话历史中，包括文本和文件信息。
    
        参数:
        input_value: 包含用户输入文本和文件的字典。
        state_value: 包含对话状态的字典，将在此字典中更新对话历史。
    
        返回:
        更新后的state_value对象。
        """
        # 检查对话ID是否存在，如果不存在则生成新的对话ID和历史记录
        if not state_value["conversation_id"]:
            random_id = str(uuid.uuid4())
            history = []
            state_value["conversation_id"] = random_id
            state_value["conversations_history"][random_id] = history
            state_value["conversations"].append({
                "label": input_value["text"],
                "key": random_id
            })
    
        # 获取当前对话的历史记录
        history = state_value["conversations_history"][state_value["conversation_id"]]
        
        # 将用户的消息添加到历史记录中，包括文本和文件信息
        history.append({
            "role": "user",
            "content": [
                {"type": "file", "content": [f for f in input_value["files"]]},
                {"type": "text", "content": input_value["text"]}
            ]
        })
        
        # 返回更新后的state_value
        return gr.update(value=state_value)

    @staticmethod
    def preprocess_submit(clear_input=True):
        
        def preprocess_submit_handler(state_value):
            """
            实际执行预处理操作的处理函数。

            该函数根据传入的`state_value`（状态值）来更新界面元素的状态，包括：
            - 根据`clear_input`参数决定是否清空输入框。
            - 更新会话列表的显示状态，禁用其他会话项。
            - 禁用添加会话和清除按钮。
            - 更新聊天机器人的显示内容和配置。
            - 更新状态值。

            参数:
            - state_value (dict): 当前的应用状态值，包含会话历史、会话ID等信息。

            返回:
            - dict: 包含所有界面元素更新操作的字典。
            """
            # 获取当前会话的历史记录
            history = state_value["conversations_history"][
                state_value["conversation_id"]]
            return {
                # 如果需要清空输入框，则更新输入框状态为清空并设置加载中；否则仅设置加载中
                **({
                    input:
                    gr.update(value=None, loading=True) if clear_input else gr.update(loading=True),
                } if clear_input else {}),
                # 更新会话列表的显示状态，禁用非当前会话项
                conversations:
                gr.update(active_key=state_value["conversation_id"],
                          items=list(
                              map(
                                  lambda item: {
                                      **item,
                                      "disabled":
                                      True if item["key"] != state_value[
                                          "conversation_id"] else False,
                                  }, state_value["conversations"]))),
                # 禁用添加会话按钮
                add_conversation_btn:
                gr.update(disabled=True),
                # 禁用清除按钮
                clear_btn:
                gr.update(disabled=True),
                # 禁用删除会话菜单项
                conversation_delete_menu_item:
                gr.update(disabled=True),
                # 更新聊天机器人的显示内容和配置，禁用部分操作
                chatbot:
                gr.update(value=history,
                          bot_config=bot_config(
                              disabled_actions=['edit', 'retry', 'delete']),
                          user_config=user_config(
                              disabled_actions=['edit', 'delete'])),
                # 更新状态值
                state:
                gr.update(value=state_value),
            }

        return preprocess_submit_handler

    @staticmethod
    def postprocess_submit(state_value):
        """
        处理提交后的操作，主要用于更新界面元素的状态和内容。
        
        参数:
        - state_value: 包含应用状态的字典，用于访问和更新应用的状态。
        
        返回:
        返回一个字典，包含多个界面元素的更新指令，用于更新应用界面。
        """
        # 获取当前对话的历史记录
        history = state_value["conversations_history"][
            state_value["conversation_id"]]
        
        # 返回一个字典，包含多个界面元素的更新指令
        return {
            input: gr.update(loading=False),  # 更新输入框状态
            conversation_delete_menu_item: gr.update(disabled=False),  # 更新删除对话菜单项状态
            clear_btn: gr.update(disabled=False),  # 更新清除按钮状态
            conversations: gr.update(items=state_value["conversations"]),  # 更新对话列表
            add_conversation_btn: gr.update(disabled=False),  # 更新添加对话按钮状态
            chatbot: gr.update(
                value=history,  # 更新聊天机器人对话历史
                bot_config=bot_config(),  # 更新机器人配置
                user_config=user_config()  # 更新用户配置
            ),
            state: gr.update(value=state_value),  # 更新应用状态
        }

    @staticmethod
    def cancel(state_value):
        """
        取消当前聊天请求并更新会话状态。

        参数:
        - state_value (dict): 包含当前会话状态的字典，包括会话历史和会话ID。

        功能:
        1. 从 `state_value` 中获取当前会话的历史记录。
        2. 更新历史记录中最后一条消息的状态：
        - 将 "loading" 设置为 False，表示加载已完成。
        - 将 "status" 设置为 "done"，表示消息处理完成。
        - 添加 "footer" 字段，值为 "Chat completion paused"，表示聊天已暂停。
        3. 调用 `postprocess_submit` 方法处理并返回更新后的状态值。

        返回:
        - dict: 更新后的会话状态值。
        """
        # 获取当前会话的历史记录
        history = state_value["conversations_history"][
            state_value["conversation_id"]]
        
        # 更新最后一条消息的状态
        history[-1]["loading"] = False
        history[-1]["status"] = "done"
        history[-1]["footer"] = "Chat completion paused"
        
        # 调用 postprocess_submit 方法处理并返回更新后的状态值
        return Gradio_Events.postprocess_submit(state_value)

    @staticmethod
    def delete_message(state_value, e: gr.EventData):
        """
        删除消息函数。
    
        根据给定的事件数据删除会话历史中的特定消息。
    
        参数:
        - state_value: 包含会话历史的状态值。
        - e: 事件数据，包含要删除的消息的索引。
    
        返回:
        更新后的状态值，其中包含删除特定消息后的会话历史。
        """
        # 获取要删除的消息的索引
        index = e._data["payload"][0]["index"]
        # 获取当前会话的历史记录
        history = state_value["conversations_history"][state_value["conversation_id"]]
        # 从历史记录中移除指定索引的消息
        history = history[:index] + history[index + 1:]
    
        # 更新会话历史记录
        state_value["conversations_history"][state_value["conversation_id"]] = history
    
        # 返回更新后的状态值
        return gr.update(value=state_value)

    @staticmethod
    def edit_message(state_value, chatbot_value, e: gr.EventData):
        """
        更新消息内容。
    
        本函数用于根据用户编辑操作更新消息内容。通过事件数据获取用户编辑的消息索引，
        并在会话历史中更新该消息的内容。
    
        参数:
        - state_value: 当前的会话状态值，包含会话历史等信息。
        - chatbot_value: 当前展示在聊天框中的消息值。
        - e: gr.EventData，包含编辑事件的数据，特别是编辑消息的索引。
    
        返回:
        - 更新后的会话状态值，用于保存修改后的会话历史。
        """
        # 获取编辑事件中消息的索引
        index = e._data["payload"][0]["index"]
        # 从会话历史中获取当前会话的消息列表
        history = state_value["conversations_history"][state_value["conversation_id"]]
        # 将编辑后的内容更新到会话历史中相应索引的消息中
        history[index]["content"] = chatbot_value[index]["content"]
        # 返回更新后的会话状态值
        return gr.update(value=state_value)

    @staticmethod
    def regenerate_message(state_value, e: gr.EventData):
        """
        根据给定的事件数据更新消息历史并返回更新后的消息历史和状态值。
        
        此函数用于在接收到特定事件数据后，根据事件数据中的索引值截断消息历史，
        并将更新后的消息历史和状态值返回。这对于实现消息历史的动态更新非常有用。
        
        参数:
        - state_value: 一个包含会话状态的字典，包括消息历史和会话ID。
        - e: 一个gr.EventData对象，包含触发事件的数据，特别是需要重新生成消息的索引。
        
        返回:
        - 更新后的消息历史和状态值，通过gr.update方法包装，以便在调用此函数后能够方便地更新UI组件。
        """
        # 获取事件数据中指定的索引值，这是需要重新生成消息的点。
        index = e._data["payload"][0]["index"]
        
        # 从状态值中提取当前会话的消息历史，并根据索引值进行截断。
        history = state_value["conversations_history"][
            state_value["conversation_id"]]
        history = history[:index]
        
        # 将截断后的消息历史保存回状态值中。
        state_value["conversations_history"][
            state_value["conversation_id"]] = history
        
        # custom code
        # 这里可以添加自定义代码，例如对消息历史进行额外处理。
        
        # 返回更新后的消息历史和状态值，通过gr.update方法包装。
        return gr.update(value=history), gr.update(value=state_value)

    @staticmethod
    def select_suggestion(input_value, e: gr.EventData):
        """
        更新输入值的文本内容。
    
        此函数用于根据事件数据更新输入值的文本内容。它会从事件数据中提取有效载荷，
        并用它来更新输入值的文本内容，通常用于界面交互中的建议选择逻辑。
    
        参数:
        - input_value: 包含文本的输入值，通常是一个字典。
        - e: 一个gr.EventData实例，包含事件数据，其中'_data'键对应的值是一个字典，
             包含要更新到文本中的数据，通常格式为{'payload': [新文本字符]}。
    
        返回:
        - 返回一个更新了文本值的gr对象，这通常用于直接更新界面上的组件。
        """
        # 更新文本：移除最后一个字符，并添加事件数据中的新字符
        input_value["text"] = input_value["text"][:-1] + e._data["payload"][0]
        # 返回更新后的值，用于更新界面组件
        return gr.update(value=input_value)

    @staticmethod
    def apply_prompt(input_value, e: gr.EventData):
        """
        更新输入值的文本内容，并返回更新后的输入值。
    
        该函数是一个静态方法，用于处理用户界面事件数据并更新输入值的文本内容。
        它接收一个输入值字典和一个事件数据对象，从事件数据中提取文本描述，并用它来更新输入值的文本内容。
    
        参数:
        - input_value: 一个字典，包含需要更新的输入值。
        - e: 一个gr.EventData对象，包含事件数据，特别是用户界面交互的数据。
    
        返回:
        - 返回一个更新了文本值的gr对象，具体更新内容取决于事件数据中的描述信息。
        """
        # 从事件数据中提取描述信息，并用它来更新输入值的文本内容
        input_value["text"] = e._data["payload"][0]["value"]["description"]
        
        # 返回一个更新后的gr对象，包含修改后的输入值
        return gr.update(value=input_value)

    @staticmethod
    def new_chat(state_value):
        """
        初始化新对话的函数。
    
        此函数用于处理对话重置或初始化的情况。如果传入的state_value中没有conversation_id，
        则跳过处理。否则，重置conversation_id，并返回更新后的状态。
    
        参数:
        - state_value: 一个字典，包含当前的对话状态信息。
    
        返回:
        - 如果state_value中没有conversation_id，则返回gr.skip()，表示跳过处理。
        - 否则，返回三个更新对象，分别用于更新对话状态。
        """
        # 检查是否有conversation_id，如果没有则跳过处理
        if not state_value["conversation_id"]:
            return gr.skip()
        
        # 重置conversation_id为空字符串
        state_value["conversation_id"] = ""
        
        # 返回三个更新对象，用于更新对话状态
        return gr.update(active_key=state_value["conversation_id"]), gr.update(
            value=None), gr.update(value=state_value)

    @staticmethod
    def select_conversation(state_value, e: gr.EventData):
        """
        更新对话选择。
    
        该方法用于当用户选择不同的对话时，更新当前对话的ID以及显示的对话历史。
        
        参数:
        - state_value: 当前应用的状态值，包含对话ID和对话历史等信息。
        - e: gr.EventData，包含事件数据，这里用于获取选中的对话ID。
        
        返回:
        - 如果选中的对话未改变或不存在于对话历史中，则跳过更新。
        - 否则，更新当前对话ID，并返回更新后的对话ID、对话历史和状态值。
        """
        # 获取选中的对话键
        active_key = e._data["payload"][0]
        
        # 检查当前对话ID是否与选中的对话键相同，或选中的对话键是否不存在于对话历史中
        if state_value["conversation_id"] == active_key or (
                active_key not in state_value["conversations_history"]):
            # 如果条件满足，则跳过更新
            return gr.skip()
        
        # 更新当前对话ID为选中的对话键
        state_value["conversation_id"] = active_key
        
        # 返回更新后的对话ID、对话历史和状态值
        return gr.update(active_key=active_key), gr.update(
            value=state_value["conversations_history"][active_key]), gr.update(
                value=state_value)

    @staticmethod
    def click_conversation_menu(state_value, e: gr.EventData):
        """
        处理会话菜单点击事件。
    
        当用户在图形界面上点击会话菜单时，此函数会被调用。它根据用户的操作类型
        对会话进行处理，比如删除选中的会话。
    
        参数:
        - state_value: 一个字典，保存了当前应用的状态值，包括会话列表和会话历史等信息。
        - e: 一个gr.EventData对象，包含用户操作的详细信息，比如点击事件的数据。
    
        返回:
        根据用户操作，返回不同的图形界面更新对象，用于更新会话列表和当前会话的状态。
        """
        # 获取会话ID和操作类型
        conversation_id = e._data["payload"][0]["key"]
        operation = e._data["payload"][1]["key"]
        
        # 如果用户选择的操作是删除
        if operation == "delete":
            # 从会话历史中删除该会话
            del state_value["conversations_history"][conversation_id]
            
            # 更新会话列表，移除被删除的会话
            state_value["conversations"] = [
                item for item in state_value["conversations"]
                if item["key"] != conversation_id
            ]
            
            # 如果当前选中的会话被删除
            if state_value["conversation_id"] == conversation_id:
                # 取消当前会话ID
                state_value["conversation_id"] = ""
                # 返回更新后的会话列表，以及重置当前会话和状态值的图形界面更新对象
                return gr.update(
                    items=state_value["conversations"],
                    active_key=state_value["conversation_id"]), gr.update(
                        value=None), gr.update(value=state_value)
            else:
                # 如果当前选中的会话未被删除，仅更新会话列表和状态值
                return gr.update(
                    items=state_value["conversations"]), gr.skip(), gr.update(
                        value=state_value)
        # 如果用户操作不是删除，忽略此次事件
        return gr.skip()

    @staticmethod
    def clear_conversation_history(state_value):
        """
        清除对话历史记录。
    
        当没有提供conversation_id时，此函数将跳过处理。
        如果提供了conversation_id，则会将该对话的记录清空，并更新状态值。
    
        参数:
        - state_value: 一个字典，包含对话ID和对话历史记录等状态信息。
    
        返回:
        - gr.update(value=None): 表示更新对话历史记录为None。
        - gr.update(value=state_value): 表示更新状态值。
        """
        # 检查是否提供了conversation_id，如果没有，则跳过处理
        if not state_value["conversation_id"]:
            return gr.skip()
        
        # 清空特定对话ID的对话历史记录
        state_value["conversations_history"][state_value["conversation_id"]] = []
        
        # 返回更新后的对话历史记录和状态值
        return gr.update(value=None), gr.update(value=state_value)

    @staticmethod
    def update_browser_state(state_value):
        """
        更新浏览器状态
    
        该方法用于更新浏览器的状态值，主要通过接收一个包含会话和会话历史的状态值字典，
        并返回一个更新后的字典，以供浏览器界面更新显示
    
        参数:
        state_value (dict): 包含会话和会话历史的状态值字典
    
        返回:
        gr.update: 返回一个更新后的字典，用于更新浏览器界面的状态显示
        """
        # 更新并返回包含会话和会话历史的字典
        return gr.update(value=dict(
            conversations=state_value["conversations"],
            conversations_history=state_value["conversations_history"]))

    @staticmethod
    def apply_browser_state(browser_state_value, state_value):
        """
        将浏览器状态应用于本地状态值。
    
        本函数将从浏览器状态值中获取会话和会话历史记录，并将它们分别更新到本地状态值中。
        然后，它使用更新后的值生成并返回两个更新操作，分别用于更新会话列表和本地状态值。
    
        参数:
        - browser_state_value: 包含浏览器状态的字典，包括会话和会话历史记录。
        - state_value: 本地状态值的字典，将被更新。
    
        返回:
        - 一个元组，包含两个更新操作（gr.update对象）:
          - 第一个更新操作用于更新会话列表，包含从浏览器状态中提取的会话。
          - 第二个更新操作用于更新本地状态值，包含更新后的本地状态。
        """
        # 将浏览器状态中的会话复制到本地状态
        state_value["conversations"] = browser_state_value["conversations"]
        # 将浏览器状态中的会话历史记录复制到本地状态
        state_value["conversations_history"] = browser_state_value["conversations_history"]
        # 返回更新操作，用于更新会话列表和本地状态值
        return gr.update(
            items=browser_state_value["conversations"]), gr.update(
                value=state_value)
    
    @staticmethod
    def generate_meeting_notes(state_value):
        state_value["show_homepage"] = False
        state_value["show_meeting_notes"] = True
        state_value["show_eye_outlined"] = False
        # 跳转打开新的页面
        return ( gr.update(visible= state_value["show_homepage"]),
                gr.update(visible= state_value["show_meeting_notes"]),
                gr.update(visible= state_value["show_eye_outlined"]),
                state_value)
    @staticmethod
    def back_home_page(state_value):
        state_value["show_homepage"] = True
        state_value["show_meeting_notes"] = False
        state_value["show_eye_outlined"] = False
        return ( gr.update(visible= state_value["show_homepage"]),
                gr.update(visible= state_value["show_meeting_notes"]),
                gr.update(visible= state_value["show_eye_outlined"]),
                state_value)
    
    @staticmethod
    def generate_surveillance_assistant(state_value):
        state_value["show_homepage"] = False
        state_value["show_eye_outlined"] = True
        state_value["show_meeting_notes"] = False
        return ( gr.update(visible= state_value["show_homepage"]),
                gr.update(visible= state_value["show_meeting_notes"]),
                gr.update(visible= state_value["show_eye_outlined"]),
                state_value)
    # 按钮点击事件绑定
    @staticmethod
    def on_transcribe_click(audio_file):
        if not audio_file:
            return "", "请上传有效的音频文件！"
        result = get_safe_transcription(audio_file)
        status = "语音识别完成" if "处理出错" not in result else "语音识别失败"
        return result, status

    @staticmethod
    def on_summary_click():
        result = get_safe_summary()
        status = "隐患排查完成" if "处理出错" not in result else "隐患排查失败"
        return result, status
    
    @staticmethod
    def on_meeting_summary(status):
        result = get_summary()
        return result, status
    
    @staticmethod
    def on_meeting_transcription(audio_file):
        result = get_transcription(audio_file)
        return result
    
    @staticmethod
    def on_meeting_translation(language):
        result = get_translation(language)
        return result

        
        


css = """
#chatbot {
  height: calc(100vh - 32px - 21px - 16px);
}

#chatbot .chatbot-conversations {
  height: 100%;
  background-color: var(--ms-gr-ant-color-bg-layout);
}

#chatbot .chatbot-conversations .chatbot-conversations-list {
  padding-left: 0;
  padding-right: 0;
}

#chatbot .chatbot-chat {
  padding: 32px;
  height: 100%;
}

@media (max-width: 768px) {
  #chatbot .chatbot-chat {
      padding: 0;
  }
}

#chatbot .chatbot-chat .chatbot-chat-messages {
  flex: 1;
}

.sidebar {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 50px; /* Narrow sidebar */
  background-color: #f0f0f0;
}

.sidebar button {
  margin: 10px;
  width: 40px;
  height: 40px;
}
"""


def logo():
    """
    生成并显示聊天机器人的logo。

    该函数使用了antd库的组件来构建和展示一个包含图像和文本的标题。
    它首先创建一个标题组件，设置其样式，然后在其中包含一个灵活的盒子（Flex），
    用于居中对齐图像和文本。图像为指定URL的图片，文本为"Chatbot"。
    """
    # 创建一个等级为1的标题组件，设置字体大小、内边距和外边距
    with antd.Typography.Title(level=1,
                               elem_style=dict(fontSize=24,
                                               padding=8,
                                               margin=0)):
        # 创建一个灵活的盒子布局，用于居中对齐其中的元素，并设置元素之间的间距为"small"
        with antd.Flex(align="center", gap="small", justify="center"):
            # 插入一张图片，设置其预览、alt文本、宽度和高度
            antd.Image(
                "icon.jpg",
                preview=False,
                alt="logo",
                width=50,
                height=50)
            # 在图片旁边添加文本"Chatbot"
            ms.Span("铁语通")


# 使用Gradio框架构建聊天界面，并定义事件处理逻辑

# 创建一个Gradio应用实例，应用全局样式和布局设置
with gr.Blocks(css=css, fill_width=True) as demo:
    # 初始化应用状态，包含会话历史、会话列表和当前会话ID
    state = gr.State({
        "conversations_history": {},  # 存储所有会话的历史记录
        "conversations": [],         # 当前会话的列表
        "conversation_id": "",        # 当前选中的会话ID
        "show_meeting_notes": False,  # 是否显示会议纪要
        "show_eye_outlined": False,  # 是否显示安全监察
        "show_homepage": True  # 是否显示主页
    })

    # 使用ms.Application和antdx.XProvider组件设置主题和语言环境
    with ms.Application(), antdx.XProvider(
            theme=DEFAULT_THEME, locale=DEFAULT_LOCALE), ms.AutoLoading():
        # 定义主布局为Row结构，设置间距和高度
        with antd.Row(gutter=[20, 20], wrap=False, elem_id="chatbot"):
            # 左侧侧边栏：包含三个按钮
            with antd.Col(span=1, elem_classes=["sidebar"]):
                with antd.Flex(vertical=True,
                               gap="small",
                               elem_style=dict(height="100%",
                                               alignItems="center",
                                               justifyContent="center",
                                               backgroundColor="#f0f0f0")):
                    with antd.Button(value=None,
                                     color="primary",
                                     variant="filled",
                                     block=True) as home_btn:
                        with ms.Slot("icon"):
                            antd.Icon("HomeOutlined")  # 主页
                        with ms.Slot("label"):
                            ms.Span("Home")
                    with antd.Button(value=None,
                                     color="primary",
                                     variant="filled",
                                     block=True) as meeting_notes_btn:
                        # 给按钮加标签
                        with ms.Slot("icon"):
                            antd.Icon("FileTextOutlined")
                            with ms.Slot("label"):
                                ms.Span("Meeting Notes")  # 会议纪要
                        # with ms.Slot("icon"):
                        #     antd.Icon("FileTextOutlined")  # 添加图标
                    with antd.Button(value=None,
                                     color="primary",
                                     variant="filled",
                                     block=True) as surveillance_assistant_btn:
                        with ms.Slot("icon"):
                            antd.Icon("EyeOutlined")  # 安全监察
            # 左侧列：包含Logo、新建对话按钮和会话列表
            with antd.Col(md=dict(flex="0 0 260px", span=24, order=0),
                          span=0,
                          order=1,
                          elem_classes="chatbot-conversations"):
                with antd.Flex(vertical=True,
                               gap="small",
                               elem_style=dict(height="100%")):
                    # 显示Logo
                    logo()

                    # 新建对话按钮，点击后创建新对话
                    with antd.Button(value=None,
                                     color="primary",
                                     variant="filled",
                                     block=True) as add_conversation_btn:
                        ms.Text("新对话")  # 按钮文本
                        with ms.Slot("icon"):
                            antd.Icon("PlusOutlined")  # 添加图标

                    # 会话列表组件，显示所有会话
                    with antdx.Conversations(
                            elem_classes="chatbot-conversations-list",
                    ) as conversations:
                        with ms.Slot('menu.items'):
                            # 定义会话菜单项，支持删除操作
                            with antd.Menu.Item(
                                    label="Delete", key="delete", danger=True
                            ) as conversation_delete_menu_item:
                                with ms.Slot("icon"):
                                    antd.Icon("DeleteOutlined")  # 删除图标

            # 右侧列：包含聊天机器人和输入框
            with antd.Col(flex=1, elem_style=dict(height="100%")) :
                with antd.Flex(vertical=True, elem_classes="chatbot-chat", visible=True) as main_col:
                    # 聊天机器人组件，配置欢迎信息、用户和机器人行为
                    chatbot = pro.Chatbot(
                        elem_classes="chatbot-chat-messages",
                        welcome_config=ChatbotWelcomeConfig(
                            variant="borderless",
                            icon="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp",
                            title=f"你好，我是铁语通",
                            description="",
                            
                        ),
                        user_config=user_config(),
                        bot_config=bot_config()
                    )

                    # 输入框组件，支持多模态输入（文本和图片）
                    with antdx.Suggestion(
                            items=DEFAULT_SUGGESTIONS,
                            should_trigger="""(e, { onTrigger, onKeyDown }) => {
                      switch(e.key) {
                        case '/':
                          onTrigger()
                          break
                        case 'ArrowRight':
                        case 'ArrowLeft':
                        case 'ArrowUp':
                        case 'ArrowDown':
                          break;
                        default:
                          onTrigger(false)
                      }
                      onKeyDown(e)
                    }""") as suggestion:
                        with ms.Slot("children"):
                            with pro.MultimodalInput(
                                    placeholder="Enter",
                                    upload_config=MultimodalInputUploadConfig(
                                        upload_button_tooltip="上传附件",
                                        max_count=6,
                                        accept="image/*",
                                        multiple=True)) as input:
                                with ms.Slot("prefix"):
                                    # 清除按钮，点击后清空当前会话历史
                                    with antd.Tooltip(title="清空当前会话历史"):
                                        with antd.Button(value=None, type="text") as clear_btn:
                                            with ms.Slot("icon"):
                                                antd.Icon("ClearOutlined")
                with antd.Flex(vertical=True, elem_style=dict(overflow="auto",height="100%"),visible=False) as meeting_notes_col:
                    with gr.Blocks(
                        theme="soft",  # 采用柔和主题
                        title="智能会议纪要生成器",
                        css="""
                        .gradio-container {max-width: 1200px !important; height: 100%; display: flex; flex-direction: column; overflow-y: auto;}
                        .panel {border: 1px solid #e0e0e0; border-radius: 8px; padding: 15px}
                        button {transition: all 0.3s ease}
                        button:hover {opacity: 0.8; transform: translateY(-2px)}
                        footer {visibility: hidden !important}
                        /* 新增滚动条控制 */
                        .highlight-box {
                        border: 2px solid #e0e0e0 !important;
                        border-radius: 8px;
                        max-height: 300px !important;  /* 设置最大高度 */
                        overflow-y: auto !important;  /* 启用垂直滚动条 */
                        }
                        /* 文本域高度锁定 */
                        .highlight-box textarea {
                        max-height: 280px !important;  /* 略小于容器高度 */
                        min-height: 120px !important;  /* 保持初始高度 */
                        }""",
                        ) as interface:

                        # 标题区域
                        gr.Markdown(
                            """
                        <div style="text-align:center">
                        <h1 style="color:#2c3e50">📝 智能会议纪要生成器</h1>
                        <p style="color:#7f8c8d">上传会议录音文件（MP3/WAV），自动生成结构化会议摘要</p>
                        </div>
                        """
                        )

                        # 核心功能区域
                        with gr.Row(variant="panel"):
                            # 左侧上传区域
                            with gr.Column(scale=1):
                                audio_input = gr.File(
                                    label="上传会议录音\n（支持MP3/WAV格式，文件大小<50MB）",
                                    file_types=[".mp3", ".wav"],
                                    elem_classes="panel",
                                )

                            # 中间处理区域
                            with gr.Column(scale=2):
                                transcription_output = gr.Textbox(
                                    label="语音识别结果",
                                    lines=5,
                                    placeholder="识别文本将在此显示...",
                                    show_copy_button=True,
                                    elem_classes="highlight-box",
                                )
                                summary_output = gr.Textbox(
                                    label="会议摘要",
                                    lines=10,
                                    placeholder="结构化摘要将在此生成...",
                                    show_copy_button=True,
                                    elem_classes="highlight-box",
                                )

                        # 操作按钮区域
                        with gr.Row():
                            transcribe_button = gr.Button(
                                "🎤 开始识别", variant="primary", size="sm", min_width=120
                            )
                            summary_button = gr.Button(
                                "✨ 生成纪要", variant="primary", size="sm", min_width=120
                            )

                        # 翻译功能区域
                        with gr.Row(variant="panel"):
                            with gr.Column(scale=1):
                                lang_dropdown = gr.Dropdown(
                                    ["英语", "日语", "法语"],
                                    label="翻译目标语言",
                                    interactive=True,
                                )
                            with gr.Column(scale=2):
                                fanyi_output = gr.Textbox(
                                    label="翻译结果",
                                    lines=5,
                                    show_copy_button=True,
                                    interactive=False,
                                    elem_classes="highlight-box",
                                )
                            fanyi_btn = gr.Button(
                                "🌐 立即翻译", variant="secondary", size="sm", min_width=120
                            )

                        # 使用说明
                        with gr.Accordion("使用指南", open=False):
                            gr.Markdown(
                                """
                            1. ​**上传录音**：点击上传按钮选择清晰的会议录音文件
                            2. ​**语音识别**：点击识别按钮获取文字稿（需等待处理完成）
                            3. ​**生成摘要**：文字识别完成后点击生成结构化会议纪要
                            4. ​**翻译功能**：选择目标语言后点击翻译按钮获取多语言版本
                            """
                            )
                with antd.Flex(vertical=True, visible=False) as safe_surveillance_col:
                    with gr.Blocks(theme=gr.themes.Soft()) as interface:  # 使用Soft主题
                        # 标题与描述
                        gr.Markdown(
                            """
                            # 🚧 施工作业过程安全隐患智能排查助手
                            ### 上传作业录音文件（MP3/WAV），自动排查安全隐患
                            """
                        )

                        # 文件上传与结果显示区域
                        with gr.Row():
                            with gr.Column(scale=1):
                                audio_safe_input = gr.File(label="上传作业录音", file_types=[".mp3", ".wav"])
                                gr.Markdown("支持的格式：MP3、WAV")
                            with gr.Column(scale=2):
                                safe_transcription_output = gr.Textbox(
                                    label="语音识别结果", lines=5, interactive=False
                                )
                                safe_summary_output = gr.Textbox(
                                    label="隐患排查结果", lines=10, interactive=False
                                )

                        # 操作按钮区域
                        with gr.Row():
                            transcribe_safe_button = gr.Button("开始语音识别", variant="primary")
                            summary_safe_button = gr.Button("开始隐患排查", variant="secondary")

                        # 状态提示区域
                        status_message = gr.Markdown("等待操作...")
        
    # 定义事件处理逻辑
    if save_history:
        # 如果启用了保存历史功能，初始化浏览器状态存储
        browser_state = gr.BrowserState(
            {
                "conversations_history": {},
                "conversations": [],
            },
            storage_key="ms_chatbot_storage"
        )
        # 更新浏览器状态
        state.change(fn=Gradio_Events.update_browser_state,
                     inputs=[state],
                     outputs=[browser_state])

        # 加载时应用浏览器状态
        demo.load(fn=Gradio_Events.apply_browser_state,
                  inputs=[browser_state, state],
                  outputs=[conversations, state])

    # 绑定事件处理函数
    add_conversation_btn.click(fn=Gradio_Events.new_chat,  # 新建对话
                               inputs=[state],
                               outputs=[conversations, chatbot, state])
    conversations.active_change(fn=Gradio_Events.select_conversation,  # 切换会话
                                inputs=[state],
                                outputs=[conversations, chatbot, state])
    conversations.menu_click(fn=Gradio_Events.click_conversation_menu,  # 点击会话菜单
                             inputs=[state],
                             outputs=[conversations, chatbot, state])
    chatbot.welcome_prompt_select(fn=Gradio_Events.apply_prompt,  # 选择欢迎提示
                                  inputs=[input],
                                  outputs=[input])

    clear_btn.click(fn=Gradio_Events.clear_conversation_history,  # 清空会话历史
                    inputs=[state],
                    outputs=[chatbot, state])

    suggestion.select(fn=Gradio_Events.select_suggestion,  # 选择建议
                      inputs=[input],
                      outputs=[input])
    chatbot.delete(fn=Gradio_Events.delete_message,  # 删除消息
                   inputs=[state],
                   outputs=[state])
    chatbot.edit(fn=Gradio_Events.edit_message,  # 编辑消息
                 inputs=[state, chatbot],
                 outputs=[state])
    meeting_notes_btn.click(fn=Gradio_Events.generate_meeting_notes,  # 会议纪要页面
                           inputs=[state],
                           outputs=[main_col, meeting_notes_col, safe_surveillance_col, state])
    home_btn.click(fn=Gradio_Events.back_home_page,  # 返回主页
                       inputs=[state],
                       outputs=[main_col, meeting_notes_col, safe_surveillance_col, state])
    surveillance_assistant_btn.click(fn=Gradio_Events.generate_surveillance_assistant,  # 安全监察页面
                                     inputs=[state],
                                     outputs=[main_col, meeting_notes_col, safe_surveillance_col, state])
    transcribe_button.click(
        fn=Gradio_Events.on_meeting_transcription, inputs=[audio_input], outputs=[transcription_output]
    )
    summary_button.click(fn=Gradio_Events.on_meeting_summary, inputs=None, outputs=[summary_output,status_message])
    fanyi_btn.click(fn=Gradio_Events.on_meeting_translation, inputs=[lang_dropdown], outputs=[fanyi_output])
    transcribe_safe_button.click(
        fn=Gradio_Events.on_transcribe_click,
        inputs=audio_safe_input,
        outputs=[safe_transcription_output, status_message],
    )
    summary_safe_button.click(
        fn=Gradio_Events.on_summary_click,
        inputs=None,
        outputs=[safe_summary_output, status_message],
    )
    

    # 处理重试事件
    regenerating_event = chatbot.retry(
        fn=Gradio_Events.regenerate_message,
        inputs=[state],
        outputs=[chatbot, state]
    ).then(fn=Gradio_Events.preprocess_submit(clear_input=False),
           inputs=[state],
           outputs=[
               input, clear_btn, conversation_delete_menu_item,
               add_conversation_btn, conversations, chatbot,
               state
           ]).then(fn=Gradio_Events.submit,
                  inputs=[state],
                  outputs=[chatbot, state])

    # 处理提交事件
    submit_event = input.submit(
        fn=Gradio_Events.add_user_message,
        inputs=[input, state],
        outputs=[state]
    ).then(fn=Gradio_Events.preprocess_submit(clear_input=True),
           inputs=[state],
           outputs=[
               input, clear_btn, conversation_delete_menu_item,
               add_conversation_btn, conversations, chatbot,
               state
           ]).then(fn=Gradio_Events.submit,
                  inputs=[state],
                  outputs=[chatbot, state])

    # 提交和重试事件完成后更新界面状态
    regenerating_event.then(fn=Gradio_Events.postprocess_submit,
                           inputs=[state],
                           outputs=[
                               input, conversation_delete_menu_item,
                               clear_btn, conversations, add_conversation_btn,
                               chatbot, state
                           ])
    submit_event.then(fn=Gradio_Events.postprocess_submit,
                      inputs=[state],
                      outputs=[
                          input, conversation_delete_menu_item, clear_btn,
                          conversations, add_conversation_btn, chatbot, state
                      ])

    # 取消事件处理
    input.cancel(fn=Gradio_Events.cancel,
                 inputs=[state],
                 outputs=[
                     input, conversation_delete_menu_item, clear_btn,
                     conversations, add_conversation_btn, chatbot, state
                 ],
                 cancels=[submit_event, regenerating_event],
                 queue=False)

if __name__ == "__main__":
    demo.queue().launch(ssr_mode=False)